package imageUpload

import (
	"errors"
	"fmt"
	"github.com/gogf/gf/frame/g"
	"github.com/gogf/gf/net/ghttp"
	"github.com/gogf/gf/os/glog"
	imageType "github.com/mushroomsir/image-type"
	"github.com/nfnt/resize"
	"github.com/rwcarlsen/goexif/exif"
	"image"
	"image/jpeg"
	_ "image/png"
	"os"
)

// 判断数组是否包含
func inArray(target string, str_array []string) bool {
	for _, element := range str_array {
		if target == element {
			return true
		}
	}
	return false
}

// png图片没有Orientation信息
func readOrientation(file *ghttp.UploadFile) int {
	tmpFile, err := file.Open()
	defer tmpFile.Close()
	if err != nil {
		return 0
	}
	x, err := exif.Decode(tmpFile)
	if err != nil {
		fmt.Println("readOrientation01, err: ", err)
		return 0
	}

	orientation, err := x.Get(exif.Orientation)
	if err != nil {
		fmt.Println("readOrientation02, err: ", err)
		return 0
	}
	orientVal, err := orientation.Int(0)
	if err != nil {
		fmt.Println("readOrientation03, err: ", err)
		return 0
	}
	return orientVal
}

// 旋转图片
func rotateImage(m image.Image, angle int) image.Image {
	switch angle {
	case 90:
		rotate90 := image.NewRGBA(image.Rect(0, 0, m.Bounds().Dy(), m.Bounds().Dx()))
		// 矩阵旋转
		for x := m.Bounds().Min.Y; x < m.Bounds().Max.Y; x++ {
			for y := m.Bounds().Max.X - 1; y >= m.Bounds().Min.X; y-- {
				//  设置像素点
				rotate90.Set(m.Bounds().Max.Y-x, y, m.At(y, x))
			}
		}
		return rotate90
	case 180:
		rotate180 := image.NewRGBA(image.Rect(0, 0, m.Bounds().Dx(), m.Bounds().Dy()))
		// 矩阵旋转
		for x := m.Bounds().Min.X; x < m.Bounds().Max.X; x++ {
			for y := m.Bounds().Min.Y; y < m.Bounds().Max.Y; y++ {
				//  设置像素点
				rotate180.Set(m.Bounds().Max.X-x, m.Bounds().Max.Y-y, m.At(x, y))
			}
		}
		return rotate180
	case 270:
		rotate270 := image.NewRGBA(image.Rect(0, 0, m.Bounds().Dy(), m.Bounds().Dx()))
		// 矩阵旋转
		for x := m.Bounds().Min.Y; x < m.Bounds().Max.Y; x++ {
			for y := m.Bounds().Max.X - 1; y >= m.Bounds().Min.X; y-- {
				// 设置像素点
				rotate270.Set(x, m.Bounds().Max.X-y, m.At(y, x))
			}
		}
		return rotate270
	}

	return nil
}

// CheckImageType 判断图片格式
func CheckImageType(file *ghttp.UploadFile) error {
	tmpFile, err := file.Open()
	defer tmpFile.Close()
	if err != nil {
		return err
	}

	res, err := imageType.Parse(tmpFile)
	if err != nil {
		glog.Println("imageType ", err.Error())
		return err
	}
	allowTypes := g.Cfg().GetStrings("upload.AllowTypes")
	if !inArray(res.Type, allowTypes) {
		return errors.New("不支持当前类型")
	}

	return nil
}

// 压缩图片
func compressionImage(file *ghttp.UploadFile, outPath string, width, height uint) error {
	tmpFile, err := file.Open()
	defer tmpFile.Close()
	if err != nil {
		return err
	}

	img, _, err := image.Decode(tmpFile)
	if err != nil {
		glog.Println("compressionImage ", err.Error())
		return err
	}

	// 转向图片
	ori := readOrientation(file) //先读取该图片的原始方向
	//根据图片原始信息的Orientation判断需要转多少度
	if ori == 6 {
		img = rotateImage(img, 90)
	}
	if ori == 3 {
		img = rotateImage(img, 180)
	}
	if ori == 8 {
		img = rotateImage(img, 270)
	}

	//压缩图片2
	m := resize.Resize(width, height, img, resize.Lanczos3)
	out, err := os.Create(outPath)
	if err != nil {
		return err
	}
	defer out.Close()
	err = jpeg.Encode(out, m, nil)
	if err != nil {
		return err
	}

	return nil
}

// 上传
// file goframe的上传文件对象
// savePath 保存路径，本地
func Upload(file *ghttp.UploadFile, savePath string) error {
	// 判断图片格式
	err := CheckImageType(file)
	if err != nil {
		return err
	}
	var width uint = 1000
	var height uint = 0
	//压缩图片
	err = compressionImage(file, savePath, width, height)
	if err != nil {
		return err
	}

	return nil
}
